/*
 * Created by SharpDevelop.
 * User: phtrung
 * Date: 5/18/2010
 * Time: 2:39 PM
 * 
 * To change this template use Tools | Options | Coding | Edit Standard Headers.
 */

using System;
using System.Collections.Generic;
using System.Collections;
using System.Drawing;
using System.Windows.Forms;
using System.IO;
using popLib;
using System.Data;

namespace CSSSpriteDesigner
{
	/// <summary>
	/// Description of MainForm.
	/// </summary>
	public partial class MainForm : Form
	{
		bool mouseClicked = false;
        string datasetStructure = "Images[ path, type ] & Canvas [ width, height, path ]";
        List<ImageInfo> exceptImage;
		public MainForm()
		{
			//
			// The InitializeComponent() call is required for Windows Forms designer support.
			//
			InitializeComponent();

            exceptImage = new List<ImageInfo>();

			#region rezise groupbox
			label1.MouseDown += delegate {  mouseClicked = true; };
			label1.MouseUp += delegate {  mouseClicked = false; };
			label1.MouseMove += delegate(object sender, System.Windows.Forms.MouseEventArgs e) { 
				if (mouseClicked)
			    {
			        this.groupBox1.Height = label1.Top + e.Y;
			        this.groupBox1.Width = label1.Left + e.X;
			        groupBox1.Text = "Preview("+panel1.Width+"x"+panel1.Height+")";
			        groupBox1.Update();
			    }
			};
			#endregion
			
			#region Button action
			button1.Click += delegate { 
				ReturnSet rs = FormLib.folderBrowser(); 
				if( rs.Success ){
					textBox1.Text = rs.Result + "";
					ListAllImage( textBox1.Text );
				}
			};
			
			button2.Click += delegate { 
				ListAllImage( textBox1.Text );
			};
			
			btn_save.Click += delegate { 
				string saveFile = FormLib.saveFile( "CSS Sprite File(*.cssprite)|*.cssprite" );
				if( !StringLib.isValid(saveFile) ) return;
				string savePath = Path.GetDirectoryName(saveFile);
				
				DataSet ds = DataLib.initDataSet( datasetStructure );
				
				foreach( Control control in flowLayoutPanel1.Controls )				
					ds.Tables["Images"].Rows.Add( new string[]{ ((ImageInfo)control.Tag).Path, "normal" } );
				
				foreach( Control control in pnl_horizon.Controls )
					ds.Tables["Images"].Rows.Add( new string[]{ ((ImageInfo)control.Tag).Path, "horizon" } );
				
				foreach( Control control in pnl_vertical.Controls )
					ds.Tables["Images"].Rows.Add( new string[]{ ((ImageInfo)control.Tag).Path, "vertical" } );

                foreach( ImageInfo info in exceptImage )
                    ds.Tables["Images"].Rows.Add(new string[] { info.Path, "include" });

				
				ds.Tables["Canvas"].Rows.Add( new object[]{ groupBox1.Width, groupBox1.Height, textBox1.Text } );                
				
				ds.WriteXml( saveFile );
				
				FormLib.alert( "Save config file done.\r\n" + saveFile );
			};
			
			btn_load.Click += delegate { 
				ReturnSet rs = FormLib.openFile( "CSS Sprite File(*.cssprite)|*.cssprite" );
				if( rs.Success ){					
					DataSet ds = DataLib.initDataSet( datasetStructure );
					ds.ReadXml( rs.Result.ToString() );

                    ResetData();
					
					foreach( DataRow row in ds.Tables["Images"].Rows ){
						Label label = initImagePiece(row["path"].ToString());
						
						switch( row["type"].ToString() ){
							case "normal": flowLayoutPanel1.Controls.Add(label); break;
							case "horizon": AddHorizonImage(label); break;
							case "vertical": AddVerticalImage(label); break;
                            case "include": exceptImage.Add((ImageInfo)label.Tag); break;
						}
					}					
					
					groupBox1.Size = new Size( NumberLib.getInt( ds.Tables["Canvas"].Rows[0]["width"] ), 
					                           NumberLib.getInt( ds.Tables["Canvas"].Rows[0]["height"] ));
                    				
					textBox1.Text = ds.Tables["Canvas"].Rows[0]["path"].ToString();
				}
			};

            btn_export.Click += delegate{				
				ReturnSet rs = FormLib.folderBrowser(); 
				if( !rs.Success ) return;				
				string savePath = rs.Result+"";				
				
                Bitmap background = new Bitmap( panel1.Width , panel1.Height);
                Graphics graphic = Graphics.FromImage((Image)background);

                foreach (Control control in flowLayoutPanel1.Controls)
                    PrintImage( graphic, (ImageInfo)control.Tag, new Rectangle(control.Location.X, control.Location.Y, control.Width, control.Height), "normal" );

                //to solve the problem of blur image when you spread them out.
                graphic.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;

                foreach (Control control in pnl_horizon.Controls)
                    PrintImage(graphic, (ImageInfo)control.Tag, new Rectangle(control.Location.X, control.Location.Y + flowLayoutPanel1.Height, control.Width*2, control.Height), "horizon");

                foreach (Control control in pnl_vertical.Controls)
                    PrintImage(graphic, (ImageInfo)control.Tag, new Rectangle(control.Location.X + flowLayoutPanel1.Width, control.Location.Y, control.Width, control.Height*2), "vertical");
                
                
                graphic.Save();
                background.Save( Path.Combine(savePath, "sprite.png"), System.Drawing.Imaging.ImageFormat.Png);
                
                try{
                	//copy blank.gif to destination
                	FormLib.extractEmbedResource("CSSSpriteDesigner.blank.gif", Path.Combine(savePath, "blank.gif"));
                	
                	//copy all include file to destination
                	foreach( ImageInfo imgInfo in exceptImage )
                		File.Copy( imgInfo.Path, Path.Combine( savePath, Path.GetFileName(imgInfo.Path) ) );
                }catch{}
				
                finalCss = finalCss.Replace("[CLS] ", "" );                
                FileLib.writeFile( Path.Combine(savePath, "sprite.css"), finalCss);
                
                FileLib.writeFile(Path.Combine(savePath, "sprite.html"), finalHtml);
                FormLib.alert("Save config file done.\r\n" + Path.Combine(textBox1.Text, "sprite.png"));
                
                GC.Collect();
                finalCss = finalHtml = "";
            };
			
			#endregion
			
			#region ContextMenu action
			deleteToolStripMenuItem.Click += delegate(object sender, EventArgs e) { 
				ToolStripMenuItem menuItem = (ToolStripMenuItem)sender;
				ContextMenuStrip menu = (ContextMenuStrip)menuItem.Owner;
				Control control = menu.SourceControl;				
				control.Parent.Controls.Remove(control);
                exceptImage.Add( (ImageInfo)control.Tag );
                RefreshContainer( pnl_horizon, true );
                RefreshContainer( pnl_vertical, false );
			};
			horizonImageToolStripMenuItem.Click+= delegate(object sender, EventArgs e) {
				ToolStripMenuItem menuItem = (ToolStripMenuItem)sender;
				ContextMenuStrip menu = (ContextMenuStrip)menuItem.Owner;
				Control control = menu.SourceControl;				
				flowLayoutPanel1.Controls.Remove( control );				
				AddHorizonImage( control );
				RefreshContainer( pnl_horizon, true );
                RefreshContainer( pnl_vertical, false );
			};
			verticalImageToolStripMenuItem.Click += delegate(object sender, EventArgs e) { 
				ToolStripMenuItem menuItem = (ToolStripMenuItem)sender;
				ContextMenuStrip menu = (ContextMenuStrip)menuItem.Owner;
				Control control = menu.SourceControl;				
				flowLayoutPanel1.Controls.Remove( control );				
				AddVerticalImage( control );
				RefreshContainer( pnl_horizon, true );
                RefreshContainer( pnl_vertical, false );
			};
			normalImageToolStripMenuItem.Click += delegate(object sender, EventArgs e) { 
				ToolStripMenuItem menuItem = (ToolStripMenuItem)sender;
				ContextMenuStrip menu = (ContextMenuStrip)menuItem.Owner;
				Control control = menu.SourceControl;
				control.Parent.Controls.Remove(control);
				flowLayoutPanel1.Controls.Add(control);
				RefreshContainer( pnl_horizon, true );
                RefreshContainer( pnl_vertical, false );
			};
			#endregion
			
			#region Flowlayout drag & drop action		
			flowLayoutPanel1.DragDrop += delegate(object sender, DragEventArgs e) { 
				MyWrapper wrapper = (MyWrapper)e.Data.GetData(typeof(MyWrapper));
			    Control source = wrapper.Control;
			
			    Point mousePosition = flowLayoutPanel1.PointToClient(new Point(e.X, e.Y));
			    Control destination = flowLayoutPanel1.GetChildAtPoint(mousePosition);
			
			    int indexDestination = flowLayoutPanel1.Controls.IndexOf(destination);
			    if (flowLayoutPanel1.Controls.IndexOf(source) < indexDestination)
			        indexDestination--;
			
			    flowLayoutPanel1.Controls.SetChildIndex(source, indexDestination);
			};
			
			flowLayoutPanel1.DragEnter += delegate(object sender, DragEventArgs e) { 
				if (e.Data.GetDataPresent(typeof(MyWrapper)))
			        e.Effect = DragDropEffects.Move;
			    else
			        e.Effect = DragDropEffects.None;
			};
			#endregion
			
		}

        

        #region CSSbuilder
        
        void PrintImage(Graphics graphic, ImageInfo image, Rectangle rect, string imageType)
        {            
            graphic.DrawImage(Image.FromFile(image.Path), rect);
            AddCss(image, rect, imageType);
        }
        static string mainCss = "[CLS]{\r\n\tbackground: url([IMG]);[ADD]\r\n}\r\n\r\n";
        static string imageCss = "[CLS]{\r\n\tbackground-position: [POX]px [POY]px;[ADD]\r\n}\r\n\r\n";        
        static string sizeCss = "\r\n\twidth:[WID]px;\r\n\theight:[HEI]px;";
        static string finalCss = "";


        static string imageTag = "<img src='blank.gif' class='[CLS]'> [FIL]([POX] [POY] [WID] [HEI])<BR><BR><BR><BR>";
        static string finalHtml = "<link rel=\"stylesheet\" type=\"text/css\" media=\"screen\" href=\"sprite.css\" />\r\n\r\n";
        //create css for passed image.
        void AddCss(ImageInfo image, Rectangle rect, string imageType)
        {
            
            //style.css*******************************************************************
            if (finalCss.Length == 0)
            {
                finalCss = mainCss.Replace("[CLS]", "[CLS] ." + image.Filename);                
                finalCss = finalCss.Replace("[ADD]", "");
                finalCss = finalCss.Replace("[IMG]", "sprite.png");                
            }
            else finalCss = finalCss.Replace("[CLS]", "[CLS] ." + image.Filename + ",");

            finalCss += imageCss.Replace("[CLS]", "." + image.Filename).Replace("[ADD]", sizeCss);
                       
            finalCss = finalCss.Replace("[POX]", rect.X > 0 ? "-" + rect.X : rect.X + "");
            finalCss = finalCss.Replace("[POY]", rect.Y > 0 ? "-" + rect.Y : rect.Y + "");
            if( imageType != "normal" ){
            	string replaceStr = imageType == "horizon" ? "\r\n\twidth:[WID]px;" : "\r\n\theight:[HEI]px;";
            	finalCss = finalCss.Replace(replaceStr, "");
            }
            
            finalCss = finalCss.Replace("[WID]", rect.Width + "");
            finalCss = finalCss.Replace("[HEI]", rect.Height + "");
            

            //test.html********************************************************************
            finalHtml += imageTag.Replace("[CLS]", image.Filename);
            finalHtml = finalHtml.Replace("[FIL]", image.Filename);
            finalHtml = finalHtml.Replace("[POX]", rect.X > 0 ? "-" + rect.X : rect.X + "");
            finalHtml = finalHtml.Replace("[POY]", rect.Y > 0 ? "-" + rect.Y : rect.Y + "");
            finalHtml = finalHtml.Replace("[WID]", rect.Width + "");
            finalHtml = finalHtml.Replace("[HEI]", rect.Height + "");
        }
        #endregion


        void AddVerticalImage( Control control ){			
			control.Anchor = AnchorStyles.Left | AnchorStyles.Bottom | AnchorStyles.Top;
			pnl_vertical.Controls.Add(control);
			RefreshContainer( pnl_vertical, false );
		}
		
		void AddHorizonImage(Control control){			
			control.Anchor = AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top;
			pnl_horizon.Controls.Add(control);
			RefreshContainer( pnl_horizon, true );
		}
        
        void RefreshContainer( Panel panel, bool horizon ){
        	int next = 0;
        	foreach( Control control in panel.Controls ){
        		ImageInfo info = (ImageInfo)control.Tag;
        		control.Location = new Point( horizon ? 0: next,  horizon ? next: 0 );
        		control.Size = new Size( horizon ? panel.Width : info.Width, horizon ? info.Height : panel.Height );
        		next += horizon ? control.Height : control.Width;
        	}
        }

        void ResetData() {
            flowLayoutPanel1.Controls.Clear();
            pnl_vertical.Controls.Clear();
            pnl_horizon.Controls.Clear();
            pnl_vertical.Tag = pnl_horizon.Tag = null;
            exceptImage.Clear();
        }

		void ListAllImage(string folder){
			if( !Directory.Exists(folder) ) return;
            ResetData();
			
			string[] extensions = "*.png;*.gif;*.jpg".Split(';');
			foreach( string extentsion in extensions ){
				string[] files = FileLib.getFileList( folder, extentsion, false, FileLib.SearchOption.FileOnly );			
				foreach( string file in files ){
					Label label = initImagePiece( file );
					ImageInfo info = (ImageInfo)label.Tag;
					
										
					if( info.Width == 1 && info.Height == 1 )
						flowLayoutPanel1.Controls.Add(label);
					else if( info.Width == 1 )
						AddHorizonImage(label);
					else if( info.Height == 1 )
						AddVerticalImage(label);
					else
						flowLayoutPanel1.Controls.Add(label);					
				}
			}
			
		}
		
		Label initImagePiece( string file ){
			Label label 			= new Label();
			label.Padding 			= label.Margin = new Padding(0);
			label.ContextMenuStrip 	= contextMenuStrip1;
			label.Cursor 			= Cursors.SizeAll;
			label.MouseDown 		+= MyMouseDown;
			toolTip1.SetToolTip( label, Path.GetFileName(file) );            
			
			Image img 				= Image.FromFile(file);
			label.BackgroundImage 	= img;
			label.Size 				= img.Size;
			label.Tag				= new ImageInfo( file, img.Width, img.Height );
			return label;
		}
		
		void MyMouseDown(object sender, MouseEventArgs e)
		{
			if( e.Button == MouseButtons.Right ) return;			
		    Control source = (Control)sender;
		    source.DoDragDrop(new MyWrapper(source), DragDropEffects.Move);
		}		
		
	}
	
	class ImageInfo{
		string path;
        string filename;
		int width;
		int height;
		
		public ImageInfo(string path, int width, int height){
			this.path = path;
			this.width = width;
			this.height = height;
            this.filename = System.IO.Path.GetFileNameWithoutExtension(path);
		}
                		
		public string Path{
			get{ return path; }
			set{ path = value; }
		}

        public string Filename
        {
            get { return filename; }
            set { filename = value; }
        }
		
		public int Width{
			get{ return width; }
			set{ width = value; }
		}
		
		public int Height{
			get{ return height; }
			set{ height = value; }
		}
	}
	
	class MyWrapper
	{
	    private Control control;
	
	    public MyWrapper(Control control)
	    {
	        this.control = control;
	    }
	
	    public Control Control
	    {
	        get { return control; }
	    }
	}
}
